<?php

namespace app\common\library;

use alipay\aop\AopClient;
use alipay\aop\request\AlipayTradeAppPayRequest;
use app\common\controller\Api;
use app\common\model\campsite\Order as CampsiteOrder;
use app\common\model\fittings\Order as FittingsOrder;
use app\common\model\lease\Order as LeaseOrder;
use app\common\model\modify\Order as ModifyOrder;
use app\common\model\MoneyLog;
use app\common\model\order\Order;
use app\common\model\Requirement;
use app\common\model\requirement\Lists;
use app\common\model\User;
use app\common\model\user\LevelLog;
use app\common\model\Wechat;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
use think\Db;
use think\Env;
use think\Log;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;
use wechatPay\Wxpay;


/**
 * 统一支付接口
 */
class Pay extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];
    protected $config;
    /**
     * 封装统一支付方法
     *
     */
    public static function pay($id, $attach, $userInfo, $pay_type)
    {
        switch ($attach) {
            case 'lease':
                $order = LeaseOrder::get($id);
                $money = $order['rent_price'];
                break;
            case 'campsite':
                $order = CampsiteOrder::get($id);
                $money = $order['pay_price'];
                break;
            case 'modify':
                $order = ModifyOrder::get($id);
                $money = $order['pay_price'];
                break;
            case 'fittings':
                $order = FittingsOrder::get($id);
                $money = $order['pay_price'];
                break;
        }
        if ($money <= 0) {
            $time = time();
            $order->status = 1;
            $order->paytime = $time;
        } else {
            if ($pay_type == '0') {
                $sdk = Pay::wxpay($order, $attach);
                //微信支付
            } elseif ($pay_type == '1') {
                //微信小程序支付
                $jsapi = (new Pay)->wechatPay('jsapi', $order->sn, $money, $userInfo->openid, $attach);
                $sdk = [
                    'timeStamp' => (string) $jsapi['timestamp'],
                    'nonceStr' => $jsapi['nonce'],
                    'package' => $jsapi['prepay_id'],
                    'signType' => 'RSA',
                    'paySign' => $jsapi['paySign'],
                ];
            } elseif ($pay_type == '2') {
                //余额支付
                $sdk =  Pay::yue($order, '');
            } elseif ($pay_type == '3') {
                //支付宝支付
                $sdk = Pay::alipay($order);
            }
        }
        //更换支付方式
        $order->pay_type = $pay_type;
        $order->allowField(true)->save();
        return $sdk ?? '';
    }


    /**
     * 余额支付
     *
     */
    private static function yue($data, $payPwd)
    {
        $user = User::get($data['user_id']);

        if ($user->pay_pwd != md5(md5($payPwd) . 'pcy')) {
            exception('支付密码不正确');
        }

        $totalMoney = bcadd($user->money, $user->no_money, 2);
        if ($data['pay_money'] > $totalMoney) {
            exception('余额不足');
        }
        Db::startTrans();
        try {
            if ($user->no_money > $data['pay_money']) {
                MoneyLog::income($user->id, $data['pay_money'], 1, 503, $data['sn']);
            } else {
                if ($user->no_money > 0) {
                    $money = bcsub($data['pay_money'], $user->no_money, 2);
                    MoneyLog::income($user->id, $user->no_money, 1, 503, $data['sn']);
                } else {
                    $money = $data['pay_money'];
                }
                if ($money > 0) {
                    MoneyLog::income($user->id, $money, 1, 504, $data['sn']);
                }
            }

            self::orderFulfillment($data['sn']);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            return $e->getMessage();
        }
        return true;
    }
    /**
     * 支付宝支付
     *
     */
    private static function alipay($data)
    {
        if (Env::get('app.debug') == true) {
            $data['pay_money'] = 0.01;
        }
        $aop = new AopClient();
        $object['out_trade_no'] = $data['sn'];
        $object['total_amount'] = $data['pay_money'];
        $object['subject'] = '订单支付';
        $json = json_encode($object);
        $request = new AlipayTradeAppPayRequest();
        $request->setNotifyUrl(cdnurl('/api/notify/alipayNotify', true));
        $request->setBizContent($json);
        $result = $aop->sdkExecute($request);
        return $result;
    }
    //小程序下单
    // private  function mnpPay($sn, $money, $openid, $attach = 'order')
    // {
    //     $jsapi = Wechat::get(['type' => 'jsapi']);
    //     // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
    //     $merchantPrivateKeyInstance = Rsa::from("file://" . ROOT_PATH  . str_replace('/', DS, substr('/application/certs/apiclient_key.pem', 1)), Rsa::KEY_TYPE_PRIVATE);
    //     // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
    //     $platformPublicKeyInstance = Rsa::from("file://" . ROOT_PATH  . str_replace('/', DS, substr('/application/certs/wechatpay.pem', 1)), Rsa::KEY_TYPE_PUBLIC);
    //     $merchantCertificateSerial = $jsapi->serial_no;
    //     // 从「微信支付平台证书」中获取「证书序列号」
    //     $platformCertificateSerial = PemUtil::parseCertificateSerialNo("file://" . ROOT_PATH  . str_replace('/', DS, substr('/application/certs/wechatpay.pem', 1)));
    //     // 构造一个 APIv3 客户端实例
    //     $instance = Builder::factory([
    //         'mchid'      => $jsapi->mch_id,
    //         'serial'     => $merchantCertificateSerial,
    //         'privateKey' => $merchantPrivateKeyInstance,
    //         'certs'      => [
    //             $platformCertificateSerial => $platformPublicKeyInstance,
    //         ],
    //     ]);
    //     try {
    //         // 发送请求
    //         $resp = $instance->chain('v3/pay/transactions/jsapi')->post(
    //             [
    //                 'json' => [
    //                     'appid' =>  $jsapi->appid,
    //                     'mchid'      => $jsapi->mch_id,
    //                     'out_trade_no'  => $sn,
    //                     'attach'  => $attach,
    //                     'description'  => '商品购买',
    //                     'notify_url'  => cdnurl($jsapi->notify_url, true),
    //                     'amount' => [
    //                         'total'    => $money * 100,
    //                         'currency' => 'CNY',
    //                     ],
    //                     'scene_info' => [
    //                         'payer_client_ip' => $_SERVER["REMOTE_ADDR"],
    //                     ],
    //                     'payer' => [
    //                         'openid' => $openid,
    //                     ]
    //                 ],
    //             ]
    //         );

    //         $res = json_decode($resp->getBody(), 1);


    //         return ['code' => 0, 'data' => $data];
    //     } catch (\Exception $e) {
    //         // 进行错误处理
    //         if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
    //             $r = $e->getResponse();
    //             echo $r->getBody();
    //         }
    //     }
    // }

    private static function wechatPay($type, $sn, $money, $openid, $attach = 'order')
    {
        try {
            $nonce = Formatter::nonce();
            $timestamp = (string) Formatter::timestamp();
            // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
            $merchantPrivateKeyInstance = Rsa::from("file://" . ROOT_PATH  . str_replace('/', DS, substr('/application/certs/apiclient_key.pem', 1)), Rsa::KEY_TYPE_PRIVATE);
            $remoteSigner = function (RequestInterface $request) use ($merchantPrivateKeyInstance, $nonce, $timestamp): string {
                $signature = Rsa::sign(Formatter::request(
                    $request->getMethod(),
                    $request->getRequestTarget(),
                    $timestamp,
                    $nonce,
                    $request->getBody()
                ), $merchantPrivateKeyInstance);
                return $signature;
            };
            $wechat = Wechat::get(['type' => $type]);

            // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
            $platformPublicKeyInstance = Rsa::from("file://" . ROOT_PATH  . str_replace('/', DS, substr('/application/certs/wechatpay.pem', 1)), Rsa::KEY_TYPE_PUBLIC);
            $merchantCertificateSerial = $wechat->serial_no;
            // 从「微信支付平台证书」中获取「证书序列号」
            $platformCertificateSerial = PemUtil::parseCertificateSerialNo("file://" . ROOT_PATH  . str_replace('/', DS, substr('/application/certs/wechatpay.pem', 1)));
            // 构造一个 APIv3 客户端实例
            $instance = Builder::factory([
                'mchid'      => $wechat->mch_id,
                'serial'     => $merchantCertificateSerial,
                'privateKey' => $merchantPrivateKeyInstance,
                'certs'      => [
                    $platformCertificateSerial => $platformPublicKeyInstance,
                ],
            ]);
            $stack = $instance->getDriver()->select()->getConfig('handler');
            // 卸载SDK内置签名中间件
            $stack->remove('signer');
            // 注册内网远程请求签名中间件
            $stack->before('prepare_body', Middleware::mapRequest(
                static function (RequestInterface $request) use ($remoteSigner, $timestamp, $nonce, $merchantCertificateSerial, $wechat): RequestInterface {
                    return $request->withHeader('Authorization', Formatter::authorization(
                        $wechat->mch_id,
                        $nonce,
                        $remoteSigner($request),
                        $timestamp,
                        $merchantCertificateSerial
                    ));
                }
            ), 'signer');
            if (Env::get('app.debug') == true) {
                $money = 0.01;
            }
            $json = [
                'appid' =>  $wechat->appid,
                'mchid'      => $wechat->mch_id,
                'out_trade_no'  => $sn,
                'attach'  => $attach,
                'description'  => '商品购买',
                'notify_url'  => cdnurl($wechat->notify_url, true),
                'amount' => [
                    'total'    => $money * 100,
                    'currency' => 'CNY',
                ],
                'scene_info' => [
                    'payer_client_ip' => $_SERVER["REMOTE_ADDR"],
                ]
            ];
            if ($type == 'jsapi') {
                $json['payer'] = [
                    'openid' =>$openid,
                ];
            }

            $resp = $instance
                ->chain("v3/pay/transactions/{$type}")->post([
                    'json' => $json,
                ]);

            $res = json_decode($resp->getBody(), 1);
            if ($type == 'jsapi') {
                $prepay_id =  'prepay_id=' .  $res['prepay_id'];
            } else {
                $prepay_id =    $res['prepay_id'];
            }
            $paySign = Wxpay::getWechartSign($wechat->appid, $timestamp, $nonce, $prepay_id);
            return compact('paySign', 'prepay_id', 'nonce', 'timestamp');
            if ($type == 'jsapi') {
                $payData = [
                    'timeStamp' => (string) $timestamp,
                    'nonceStr' => $nonce,
                    'package' => $prepay_id,
                    'signType' => 'RSA',
                    'paySign' => $paySign
                ];
            } else {
                $payData = [
                    'appid' => $wechat->appid,
                    'partnerid' => $wechat->mch_id,
                    'prepayid' => $prepay_id,
                    'package' => "Sign=WXPay",
                    'noncestr' => $nonce,
                    'timestamp' => (string) $timestamp,
                    'sign' => $paySign
                ];
            }
            return $payData;
        } catch (\Exception $e) {
            // 进行错误处理
            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r = $e->getResponse();
                $msg = json_decode($r->getBody(), 1);
                exception($msg['message']);
            }
            exception($e->getMessage());
        }
    }




    //小程序下单
    public static function minipay($sn, $pay_fee, $openid, $attach = 'order')
    {
        $out_trade_no = $sn;
        $money = $pay_fee;
        if (Env::get('app.debug') == true) {
            $money = 0.01;
        }
        if (empty($out_trade_no)) {
            exception('缺少参数order_sn');
        }
        // 官方提供网址
        $url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
        $urlarr = parse_url($url); //拆解为：[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/native]
        $time = time(); //时间戳
        $noncestr = Wxpay::getNonceStr();
        $appid = config('site.appid'); //appID
        $mchid = config('site.mch_id'); //商户ID
        $xlid =  config('site.serial_no'); //证书序列号
        $data = array();
        $data['appid'] = $appid;
        $data['mchid'] = $mchid;
        $data['attach'] = $attach;
        $data['description'] = '商品描述'; //商品描述
        $data['out_trade_no'] = $out_trade_no; //订单编号，订单号在微信支付里是唯一的
        $data['notify_url'] =  cdnurl('/api/notify/wechatNotify', true); //需根据自己的情况修改回调接口，也可以为空
        $data['amount']['total'] = $money * 100; //金额 单位 分
        $data['scene_info']['payer_client_ip'] = $_SERVER["REMOTE_ADDR"];; //场景ip
        $data['payer']['openid'] = $openid; //openid
        $array = json_encode($data, JSON_UNESCAPED_UNICODE);
        //签名，包含了$data数据、微信指定地址、随机数和时间
        $key = Wxpay::getSign($array, $urlarr['path'], $noncestr, $time);
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', $mchid, $xlid, $noncestr, $time, $key);
        //头部信息
        $header  = array(
            'Accept: application/json',
            'Content-Type: application/json',
            'User-Agent:*/*',
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token
        );
        $res = Wxpay::curl_post_https($url, $array, $header);
        $prepay_id = json_decode($res, true)['prepay_id'];
        $paySign = Wxpay::getWechartSign($appid, $time, $noncestr, 'prepay_id=' . $prepay_id);
        $payData = [
            'timeStamp' => (string) $time,
            'nonceStr' => $noncestr,
            'package' => 'prepay_id=' . $prepay_id,
            'signType' => 'RSA',
            'paySign' => $paySign
        ];
        return $payData;
    }
    // php -f D:\phpstudy_pro\WWW\1255\vendor\wechatpay\wechatpay\bin\CertificateDownloader.php -- -k QbyyrkXYWbwSVT3kw3FwBj1xv9b8rLLu -m 1586569011 -f C:\Users\Administrator\Desktop\1586569011_20230628_cert\apiclient_key.pem -s 63005C1EB8FE15AF1EA278F9C3F774D168929FCD -o C:\Users\Administrator\Desktop\1586569011_20230628_cert\
    // 0 1 * * *  /usr/bin/php /www/wwwroot/1214test.ciyuantiaoyue.com/1214-3.0/public/index.php /addons/crontab/autotask/index
    //微信app支付
    private static function wxpay($order,  $attach)
    {
        $out_trade_no = $order['sn'];
        $money = $order['pay_money'];
        if (Env::get('app.debug') == true) {
            $money = 0.01;
        }
        if (empty($out_trade_no)) {
            exception('缺少参数order_sn');
        }
        // 官方提供网址
        $url = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
        $urlarr = parse_url($url); //拆解为：[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/native]
        $time = time(); //时间戳
        $noncestr = Wxpay::getNonceStr();
        $appid = config('site.app_id'); //appID
        $mchid = config('site.mch_id'); //商户ID
        $xlid =  config('site.serial_no'); //证书序列号
        $data = array();
        $data['appid'] = $appid;
        $data['mchid'] = $mchid;
        $data['attach'] = $attach;
        $data['description'] = '商品描述'; //商品描述
        $data['out_trade_no'] = $out_trade_no; //订单编号，订单号在微信支付里是唯一的
        $data['notify_url'] =  cdnurl('/api/notify/wechatNotify', true); //需根据自己的情况修改回调接口，也可以为空
        $data['amount']['total'] = $money * 100; //金额 单位 分
        $data['scene_info']['payer_client_ip'] = $_SERVER["REMOTE_ADDR"];; //场景ip
        // $data['payer']['openid'] = $openid; //app支付不需要openid
        $data = json_encode($data);

        //签名，包含了$data数据、微信指定地址、随机数和时间
        $key = Wxpay::getSign($data, $urlarr['path'], $noncestr, $time);
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', $mchid, $xlid, $noncestr, $time, $key);
        //头部信息
        $header  = array(
            'Accept: application/json',
            'Content-Type: application/json',
            'User-Agent:*/*',
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token
        );
        //向微信接口地址提交json格式的$data和header的头部信息，得到返回值
        $res = Wxpay::curl_post_https($url, $data, $header);
        $prepay_id = json_decode($res, true)['prepay_id'];


        $paySign = Wxpay::getWechartSign($appid, $time, $noncestr, $prepay_id);
        $payData = [
            'appid' => $appid,
            'partnerid' => $mchid,
            'prepayid' => $prepay_id,
            'package' => "Sign=WXPay",
            'noncestr' => $noncestr,
            'timestamp' => (string) $time,
            'sign' => $paySign
        ];
        return $payData;
    }
    //会员开通成功
    public static function vipFulfillment($id, $trade_no = null)
    {
        $log = LevelLog::get($id);
        if (!$log) {
            exception('订单不存在');
        }
    }
    //订单支付成功
    public static function orderFulfillment($sn, $trade_no = null)
    {

        try {
            $order = Order::get([
                'status' => 0,
                'sn' => $sn,
            ]);

            if (!$order) {
                exception('订单不存在');
            }

            // $user = User::get($order->user_id);
            // dd($order->distribution == '2');


            // if ($order->distribution == '2') {
            //     $data['status'] = 2;

            //     $data['qh_image'] = build($order->id);
            // }

            $order->transaction_id = $trade_no;
            $order->paytime = time();
            $order->status = '10';
            $order->save();
            // $user->setInc('consumption', $order->pay_money);

        } catch (\Exception $e) {
            exception($e);
        }
    }
}
